package com.google.code.coma.producer;

import com.google.code.coma.Coma;
import com.google.code.coma.domain.Part;
import com.google.code.coma.domain.Type;
import com.google.code.coma.producer.publisher.PartPublisher;
import com.google.code.coma.space.util.SpaceManager;
import com.google.code.coma.worker.AbstractWorker;
import com.google.code.coma.worker.Worker;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozartspaces.core.*;

import java.net.URI;
import java.util.*;

/**
 * Standalone producer. This publishes produced parts by using a publisher.
 *
 * @author Dominik Strasser, dominikstr@gmail.com
 */
public abstract class StandaloneProducer extends AbstractWorker implements Worker {
	private static final Log log = LogFactory.getLog(StandaloneProducer.class);

	private Type type;
	private int amount;
	private String producerId;
	private int faultPercentage;

	private Thread executionThread;

	private PartPublisher partPublisher;

	private static final String[] cpuTypes = {"1_6_Single_Core", "2_0_Dual_Core", "2_4_Quad_Core"};

	private boolean sleep;

	public StandaloneProducer(String factoryId, Integer amount, Type type, Integer faultPercentage, PartPublisher partPublisher, boolean sleep) {
		super(factoryId);

		this.amount = amount;
		this.type = type;
		this.faultPercentage = faultPercentage;

		//every producer has to be identified
		producerId = "producer_" + UUID.randomUUID().toString();

		this.partPublisher = partPublisher;
		this.sleep = sleep;
	}

	@Override
	public void startWork() {
		executionThread = new Thread(new Runnable() {
			@Override
			public void run() {
				int procuded = 0;
				if (log.isInfoEnabled())
					log.info("Starting producer");
				while (!Thread.currentThread().isInterrupted() && procuded < amount) {
					Part p;
					if (type == Type.CPU)
						p = new Part(type, producerId, new Random().nextInt(100) < faultPercentage, cpuTypes[new Random().nextInt(3)]);
					else
						p = new Part(type, producerId, new Random().nextInt(100) < faultPercentage);
					try {
						partPublisher.publish(p);
						if (log.isDebugEnabled())
							log.debug("created " + p.getType() + " with id" + p.getId());
						procuded++;
					} catch (Exception e) {
						//just log the message and try it again
						log.error("Error writing created part", e);
					}
					if (sleep && procuded < amount) {
						//sleep onyl if not finished
						try {
							Thread.sleep((new Random().nextInt(3) + 1) * 1000);
						} catch (InterruptedException e) {
							break;
						}
					}
				}
				if (log.isInfoEnabled())
					log.info("Stopped working");

				partPublisher.shutdown();
			}
		}, producerId);
		executionThread.start();
	}

	@Override
	public void stopWork() {
		if (executionThread != null) {
			//just interrupt the thread
			executionThread.interrupt();
		}
	}

	@Override
	public String getWorkerId() {
		return producerId;
	}

	@Override
	public boolean isActive() {
		return executionThread.isAlive();
	}
}
